/**
 * 存储错误处理器
 * 处理LocalStorage、IndexedDB等存储相关错误
 * 提供内存存储降级方案确保游戏数据在存储失败时仍能正常工作
 * @class
 */

export interface StorageFallbackOptions {
  /** 是否启用内存存储降级 */
  enableMemoryFallback?: boolean
  /** 是否启用数据压缩 */
  enableDataCompression?: boolean
  /** 是否显示存储错误警告 */
  showStorageWarning?: boolean
  /** 存储配额警告阈值（字节） */
  quotaWarningThreshold?: number
  /** 自动清理旧数据的天数 */
  autoCleanupDays?: number
}

export interface StorageErrorInfo {
  /** 错误类型 */
  type: 'quota' | 'access' | 'corruption' | 'permission' | 'serialization'
  /** 错误消息 */
  message: string
  /** 错误对象 */
  error: Error
  /** 发生错误的时间戳 */
  timestamp: number
  /** 错误发生的上下文信息 */
  context?: {
    storageType?: 'localStorage' | 'indexedDB' | 'sessionStorage'
    key?: string
    dataSize?: number
    operation?: 'read' | 'write' | 'delete' | 'clear'
  }
}

/**
 * 存储错误处理器类
 */
export class StorageErrorHandler {
  private options: Required<StorageFallbackOptions>
  private isUsingMemoryFallback: boolean = false
  private memoryStorage: Map<string, any> = new Map()
  private errorHistory: StorageErrorInfo[] = []
  private maxErrorHistory: number = 50
  private errorCallbacks: Array<(error: StorageErrorInfo) => void> = []
  private storageQuotaUsage: number = 0
  private lastCleanupTime: number = 0

  /**
   * 创建存储错误处理器
   * @param options - 配置选项
   */
  constructor(options: StorageFallbackOptions = {}) {
    this.options = {
      enableMemoryFallback: options.enableMemoryFallback ?? true,
      enableDataCompression: options.enableDataCompression ?? true,
      showStorageWarning: options.showStorageWarning ?? true,
      quotaWarningThreshold: options.quotaWarningThreshold ?? 5 * 1024 * 1024, // 5MB
      autoCleanupDays: options.autoCleanupDays ?? 30
    }

    // 初始化时检查存储配额
    this.checkStorageQuota()
  }

  /**
   * 处理存储配额超出错误
   * @param error - 错误对象
   * @param key - 尝试存储的键名
   * @param data - 尝试存储的数据
   * @returns 是否成功处理错误
   */
  handleStorageQuotaExceeded(error: Error, key?: string, data?: any): boolean {
    const errorInfo: StorageErrorInfo = {
      type: 'quota',
      message: `存储配额超出: ${error.message}`,
      error,
      timestamp: Date.now(),
      context: {
        storageType: 'localStorage',
        key,
        dataSize: data ? JSON.stringify(data).length : undefined,
        operation: 'write'
      }
    }

    this.logError(errorInfo)

    // 尝试清理旧数据
    const cleanupSuccess = this.cleanupOldData()
    
    if (cleanupSuccess) {
      // 清理成功后重试存储
      try {
        if (key && data) {
          localStorage.setItem(key, JSON.stringify(data))
          console.log('清理后重新存储成功')
          return true
        }
      } catch (retryError) {
        console.error('清理后重试存储失败:', retryError)
      }
    }

    // 如果清理失败或重试失败，启用内存存储降级
    if (this.options.enableMemoryFallback) {
      return this.fallbackToMemoryStorage(key, data)
    }

    return false
  }

  /**
   * 处理存储访问错误
   * @param error - 错误对象
   * @param operation - 操作类型
   * @param key - 相关的键名
   * @returns 是否成功处理错误
   */
  handleStorageAccessError(error: Error, operation: 'read' | 'write' | 'delete', key?: string): boolean {
    const errorInfo: StorageErrorInfo = {
      type: 'access',
      message: `存储访问错误: ${error.message}`,
      error,
      timestamp: Date.now(),
      context: {
        storageType: 'localStorage',
        key,
        operation
      }
    }

    this.logError(errorInfo)

    // 检查是否是隐私模式或存储被禁用
    if (this.isStorageDisabled()) {
      console.warn('检测到存储被禁用，启用内存存储降级')
      return this.fallbackToMemoryStorage()
    }

    // 尝试使用sessionStorage作为临时替代
    if (operation === 'read' && key) {
      try {
        const sessionData = sessionStorage.getItem(key)
        if (sessionData) {
          console.log('从sessionStorage读取数据成功')
          return true
        }
      } catch (sessionError) {
        console.error('sessionStorage访问也失败:', sessionError)
      }
    }

    // 启用内存存储降级
    if (this.options.enableMemoryFallback) {
      return this.fallbackToMemoryStorage()
    }

    return false
  }

  /**
   * 处理数据损坏错误
   * @param error - 错误对象
   * @param key - 损坏数据的键名
   * @returns 是否成功处理错误
   */
  handleDataCorruption(error: Error, key: string): boolean {
    const errorInfo: StorageErrorInfo = {
      type: 'corruption',
      message: `数据损坏: ${error.message}`,
      error,
      timestamp: Date.now(),
      context: {
        storageType: 'localStorage',
        key,
        operation: 'read'
      }
    }

    this.logError(errorInfo)

    // 尝试删除损坏的数据
    try {
      localStorage.removeItem(key)
      console.log(`已删除损坏的数据: ${key}`)
      
      // 尝试从备份恢复
      const backupKey = `${key}_backup`
      const backupData = localStorage.getItem(backupKey)
      
      if (backupData) {
        localStorage.setItem(key, backupData)
        console.log(`从备份恢复数据: ${key}`)
        return true
      }
    } catch (cleanupError) {
      console.error('清理损坏数据失败:', cleanupError)
    }

    // 返回默认数据
    return this.useDefaultData(key)
  }

  /**
   * 处理序列化错误
   * @param error - 错误对象
   * @param key - 相关的键名
   * @param data - 尝试序列化的数据
   * @returns 是否成功处理错误
   */
  handleSerializationError(error: Error, key: string, data: any): boolean {
    const errorInfo: StorageErrorInfo = {
      type: 'serialization',
      message: `序列化错误: ${error.message}`,
      error,
      timestamp: Date.now(),
      context: {
        storageType: 'localStorage',
        key,
        operation: 'write'
      }
    }

    this.logError(errorInfo)

    // 尝试简化数据结构
    try {
      const simplifiedData = this.simplifyData(data)
      const serializedData = JSON.stringify(simplifiedData)
      
      localStorage.setItem(key, serializedData)
      console.log(`使用简化数据存储成功: ${key}`)
      return true
    } catch (simplifyError) {
      console.error('简化数据存储失败:', simplifyError)
    }

    // 使用内存存储
    if (this.options.enableMemoryFallback) {
      this.memoryStorage.set(key, data)
      console.log(`数据已存储到内存: ${key}`)
      return true
    }

    return false
  }

  /**
   * 处理存储权限错误
   * @param error - 错误对象
   * @returns 是否成功处理错误
   */
  handlePermissionError(error: Error): boolean {
    const errorInfo: StorageErrorInfo = {
      type: 'permission',
      message: `存储权限错误: ${error.message}`,
      error,
      timestamp: Date.now(),
      context: {
        storageType: 'localStorage',
        operation: 'access'
      }
    }

    this.logError(errorInfo)

    // 显示权限提示
    if (this.options.showStorageWarning) {
      this.showPermissionWarning()
    }

    // 启用内存存储降级
    return this.fallbackToMemoryStorage()
  }

  /**
   * 降级到内存存储
   * @param key - 可选的键名
   * @param data - 可选的数据
   * @returns 是否成功启用内存存储
   */
  private fallbackToMemoryStorage(key?: string, data?: any): boolean {
    if (!this.isUsingMemoryFallback) {
      console.warn('启用内存存储降级模式')
      this.isUsingMemoryFallback = true

      // 显示降级警告
      if (this.options.showStorageWarning) {
        this.showStorageFallbackWarning()
      }
    }

    // 如果提供了键值对，存储到内存
    if (key && data !== undefined) {
      this.memoryStorage.set(key, data)
      console.log(`数据已存储到内存: ${key}`)
    }

    return true
  }

  /**
   * 清理旧数据
   * @returns 是否成功清理
   */
  private cleanupOldData(): boolean {
    try {
      const now = Date.now()
      const cutoffTime = now - (this.options.autoCleanupDays * 24 * 60 * 60 * 1000)
      let cleanedCount = 0

      // 遍历localStorage中的所有项
      for (let i = localStorage.length - 1; i >= 0; i--) {
        const key = localStorage.key(i)
        if (!key) continue

        try {
          const item = localStorage.getItem(key)
          if (!item) continue

          // 尝试解析数据，查找时间戳
          const data = JSON.parse(item)
          
          if (data && typeof data === 'object' && data.timestamp) {
            if (data.timestamp < cutoffTime) {
              localStorage.removeItem(key)
              cleanedCount++
              console.log(`清理旧数据: ${key}`)
            }
          }
        } catch (parseError) {
          // 如果无法解析，检查是否是很久以前的数据
          // 这里可以根据键名模式来判断
          if (this.isOldDataKey(key)) {
            localStorage.removeItem(key)
            cleanedCount++
            console.log(`清理无法解析的旧数据: ${key}`)
          }
        }
      }

      this.lastCleanupTime = now
      console.log(`清理完成，共清理 ${cleanedCount} 项数据`)
      return cleanedCount > 0
    } catch (error) {
      console.error('清理旧数据失败:', error)
      return false
    }
  }

  /**
   * 检查是否是旧数据的键名
   * @param key - 键名
   * @returns 是否是旧数据
   */
  private isOldDataKey(key: string): boolean {
    // 这里可以根据应用的键名规则来判断
    const oldKeyPatterns = [
      /^game_data_\d{4}_\d{2}_\d{2}$/, // 日期格式的旧数据
      /^temp_/, // 临时数据
      /^cache_/ // 缓存数据
    ]

    return oldKeyPatterns.some(pattern => pattern.test(key))
  }

  /**
   * 简化数据结构
   * @param data - 原始数据
   * @returns 简化后的数据
   */
  private simplifyData(data: any): any {
    if (data === null || data === undefined) {
      return data
    }

    if (typeof data !== 'object') {
      return data
    }

    if (Array.isArray(data)) {
      return data.map(item => this.simplifyData(item))
    }

    // 移除循环引用和函数
    const simplified: any = {}
    
    for (const [key, value] of Object.entries(data)) {
      if (typeof value === 'function') {
        continue // 跳过函数
      }
      
      if (typeof value === 'object' && value !== null) {
        try {
          simplified[key] = this.simplifyData(value)
        } catch {
          // 跳过无法处理的对象
          continue
        }
      } else {
        simplified[key] = value
      }
    }

    return simplified
  }

  /**
   * 使用默认数据
   * @param key - 键名
   * @returns 是否成功设置默认数据
   */
  private useDefaultData(key: string): boolean {
    const defaultData = this.getDefaultDataForKey(key)
    
    if (defaultData !== null) {
      try {
        localStorage.setItem(key, JSON.stringify(defaultData))
        console.log(`使用默认数据: ${key}`)
        return true
      } catch (error) {
        // 如果localStorage失败，存储到内存
        this.memoryStorage.set(key, defaultData)
        console.log(`默认数据已存储到内存: ${key}`)
        return true
      }
    }

    return false
  }

  /**
   * 获取键的默认数据
   * @param key - 键名
   * @returns 默认数据或null
   */
  private getDefaultDataForKey(key: string): any {
    const defaultDataMap: Record<string, any> = {
      'game_settings': {
        soundEnabled: true,
        musicEnabled: true,
        masterVolume: 1.0,
        difficulty: 'normal'
      },
      'player_progress': {
        level: 1,
        score: 0,
        unlockedCharacters: ['default'],
        achievements: []
      },
      'leaderboard': {
        scores: [],
        lastUpdated: Date.now()
      }
    }

    return defaultDataMap[key] || null
  }

  /**
   * 检查存储是否被禁用
   * @returns 存储是否被禁用
   */
  private isStorageDisabled(): boolean {
    try {
      const testKey = '__storage_test__'
      localStorage.setItem(testKey, 'test')
      localStorage.removeItem(testKey)
      return false
    } catch {
      return true
    }
  }

  /**
   * 检查存储配额
   */
  private async checkStorageQuota(): Promise<void> {
    try {
      if ('storage' in navigator && 'estimate' in navigator.storage) {
        const estimate = await navigator.storage.estimate()
        const used = estimate.usage || 0
        const quota = estimate.quota || 0
        
        this.storageQuotaUsage = used
        
        if (used > this.options.quotaWarningThreshold) {
          console.warn(`存储使用量较高: ${(used / 1024 / 1024).toFixed(2)}MB / ${(quota / 1024 / 1024).toFixed(2)}MB`)
          
          if (this.options.showStorageWarning) {
            this.showQuotaWarning(used, quota)
          }
        }
      }
    } catch (error) {
      console.error('检查存储配额失败:', error)
    }
  }

  /**
   * 显示存储降级警告
   */
  private showStorageFallbackWarning(): void {
    const warning = document.createElement('div')
    warning.className = 'storage-fallback-warning'
    warning.style.cssText = `
      position: fixed;
      top: 20px;
      right: 20px;
      background: rgba(255, 152, 0, 0.9);
      color: white;
      padding: 12px 16px;
      border-radius: 6px;
      font-size: 14px;
      z-index: 1001;
      box-shadow: 0 2px 8px rgba(0,0,0,0.2);
      animation: slideInRight 0.3s ease-out;
    `
    warning.innerHTML = `
      <strong>存储提示</strong><br>
      已启用内存存储模式<br>
      <small>数据将在页面刷新后丢失</small>
    `

    document.body.appendChild(warning)

    // 8秒后移除警告
    setTimeout(() => {
      warning.remove()
    }, 8000)
  }

  /**
   * 显示权限警告
   */
  private showPermissionWarning(): void {
    const warning = document.createElement('div')
    warning.className = 'storage-permission-warning'
    warning.style.cssText = `
      position: fixed;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      background: rgba(220, 53, 69, 0.95);
      color: white;
      padding: 20px;
      border-radius: 8px;
      text-align: center;
      z-index: 1002;
      font-size: 16px;
      max-width: 400px;
    `
    warning.innerHTML = `
      <h3>存储权限受限</h3>
      <p>游戏数据无法保存到本地存储</p>
      <p>请检查浏览器设置或退出隐私模式</p>
      <button id="dismiss-storage-warning" style="
        background: white;
        color: #dc3545;
        border: none;
        padding: 8px 16px;
        border-radius: 4px;
        cursor: pointer;
        margin-top: 10px;
      ">我知道了</button>
    `

    document.body.appendChild(warning)

    // 添加按钮事件
    const dismissBtn = warning.querySelector('#dismiss-storage-warning') as HTMLButtonElement
    dismissBtn.addEventListener('click', () => {
      warning.remove()
    })

    // 15秒后自动移除
    setTimeout(() => {
      if (warning.parentNode) {
        warning.remove()
      }
    }, 15000)
  }

  /**
   * 显示配额警告
   * @param used - 已使用空间
   * @param quota - 总配额
   */
  private showQuotaWarning(used: number, quota: number): void {
    const usedMB = (used / 1024 / 1024).toFixed(1)
    const quotaMB = (quota / 1024 / 1024).toFixed(1)
    
    const warning = document.createElement('div')
    warning.className = 'storage-quota-warning'
    warning.style.cssText = `
      position: fixed;
      bottom: 20px;
      right: 20px;
      background: rgba(255, 193, 7, 0.9);
      color: #333;
      padding: 12px 16px;
      border-radius: 6px;
      font-size: 14px;
      z-index: 1001;
      box-shadow: 0 2px 8px rgba(0,0,0,0.2);
    `
    warning.innerHTML = `
      <strong>存储空间提醒</strong><br>
      已使用: ${usedMB}MB / ${quotaMB}MB<br>
      <small>建议清理旧数据</small>
    `

    document.body.appendChild(warning)

    // 10秒后移除警告
    setTimeout(() => {
      warning.remove()
    }, 10000)
  }

  /**
   * 记录错误信息
   * @param errorInfo - 错误信息
   */
  private logError(errorInfo: StorageErrorInfo): void {
    this.errorHistory.push(errorInfo)
    
    // 限制错误历史记录数量
    if (this.errorHistory.length > this.maxErrorHistory) {
      this.errorHistory.shift()
    }

    // 触发错误回调
    this.errorCallbacks.forEach(callback => {
      try {
        callback(errorInfo)
      } catch (callbackError) {
        console.error('存储错误回调执行失败:', callbackError)
      }
    })

    console.error(`[StorageErrorHandler] ${errorInfo.message}`, errorInfo.error)
  }

  /**
   * 添加错误回调函数
   * @param callback - 错误回调函数
   */
  addErrorCallback(callback: (error: StorageErrorInfo) => void): void {
    this.errorCallbacks.push(callback)
  }

  /**
   * 移除错误回调函数
   * @param callback - 要移除的回调函数
   */
  removeErrorCallback(callback: (error: StorageErrorInfo) => void): void {
    const index = this.errorCallbacks.indexOf(callback)
    if (index > -1) {
      this.errorCallbacks.splice(index, 1)
    }
  }

  /**
   * 从内存存储读取数据
   * @param key - 键名
   * @returns 存储的数据或null
   */
  getFromMemory(key: string): any {
    return this.memoryStorage.get(key) || null
  }

  /**
   * 向内存存储写入数据
   * @param key - 键名
   * @param data - 要存储的数据
   */
  setToMemory(key: string, data: any): void {
    this.memoryStorage.set(key, data)
  }

  /**
   * 检查是否使用内存存储降级
   * @returns 是否使用内存存储
   */
  isUsingMemoryFallbackMode(): boolean {
    return this.isUsingMemoryFallback
  }

  /**
   * 获取错误历史记录
   * @returns 错误历史记录数组
   */
  getErrorHistory(): StorageErrorInfo[] {
    return [...this.errorHistory]
  }

  /**
   * 获取错误统计信息
   * @returns 错误统计对象
   */
  getErrorStats(): {
    totalErrors: number
    errorsByType: Record<string, number>
    recentErrors: number
    isUsingMemoryFallback: boolean
    storageQuotaUsage: number
  } {
    const errorsByType: Record<string, number> = {}
    const recentThreshold = Date.now() - 60000 // 最近1分钟

    let recentErrors = 0

    this.errorHistory.forEach(error => {
      errorsByType[error.type] = (errorsByType[error.type] || 0) + 1
      if (error.timestamp > recentThreshold) {
        recentErrors++
      }
    })

    return {
      totalErrors: this.errorHistory.length,
      errorsByType,
      recentErrors,
      isUsingMemoryFallback: this.isUsingMemoryFallback,
      storageQuotaUsage: this.storageQuotaUsage
    }
  }

  /**
   * 清除错误历史记录
   */
  clearErrorHistory(): void {
    this.errorHistory = []
  }

  /**
   * 手动触发数据清理
   * @returns 是否成功清理
   */
  manualCleanup(): boolean {
    return this.cleanupOldData()
  }

  /**
   * 销毁存储错误处理器
   */
  destroy(): void {
    this.memoryStorage.clear()
    this.errorCallbacks = []
    this.clearErrorHistory()
  }
}

/**
 * 全局存储错误处理器实例
 */
export const storageErrorHandler = new StorageErrorHandler()